package com.qf.base.utils;


import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author 30909
 * <p>
 * 同步调用工具类
 * 解决MAX{t1,t2,t3} 的问题
 * CountDownLatch 构造方法指定一个 int 值，代表之后有几个线程
 * 每个线程执行完毕，调用CountDownLatch的countDown（）方法
 * CountDownLatch 使用方法卡住当前线程
 * 等到 CountDownLatch 方法被调用的次数达到 countDown 的值时放行
 */
public class SyncBatchCallUtil {

    /**
     * 线程池
     */
    public static ExecutorService executor;

    static {
        //核心线程数
        int corePoolSize = 5;
        //最大线程数
        int maxPoolSize = 10;
        //时间
        long keepAliveTime = 10;
        //时间单位
        TimeUnit unit = TimeUnit.SECONDS;
        //队列
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(10);
        //线程工厂
        ThreadFactory threadFactory = new AsyncBatchCallUtil.UserThreadFactory("qianfeng");
        //拒绝策略
        RejectedExecutionHandler handler = new AsyncBatchCallUtil.MyRejectPolicy();

        //实例化实例话线程池
        executor = new ThreadPoolExecutor(
                corePoolSize,
                maxPoolSize,
                keepAliveTime,
                unit,
                workQueue,
                threadFactory,
                handler
        );

    }

    /**
     * 拒绝策略
     */
    static class MyRejectPolicy implements RejectedExecutionHandler {

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            System.out.println(AsyncBatchCallUtil.class.getName() + "线程队列已经满了");
        }
    }


    /**
     * 线程工厂
     */
    static class UserThreadFactory implements ThreadFactory {

        private final String namePrefix;
        //原子
        private final AtomicInteger nextId = new AtomicInteger(1);

        public UserThreadFactory(String groupName) {
            this.namePrefix = "From" + AsyncBatchCallUtil.UserThreadFactory.class.getName() + "-" + groupName + "1";
        }

        @Override
        public Thread newThread(Runnable r) {
            String name = namePrefix + nextId.getAndIncrement();
            Thread thread = new Thread(null, r, name);
            return thread;
        }
    }

    /**
     * 自定义任务类
     */
    public static abstract class Task implements Runnable {
        /**
         * 任务调度的方法
         */
        public abstract void exe();

        /**
         * 内部封装 CountDownCatch
         */
        private CountDownLatch countDownLatch;

        public void setCountDownLatch(CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
        }


        @Override
        public void run() {
            try {
                //先执行任务
                exe();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 在执行 countDown
                countDownLatch.countDown();
            }
        }
    }


    /**
     * 创建一组任务
     */
    private static boolean createTasks(Task[] tasks) {
        //给魅每组任务实例一个 CountDownLatch
        //注意i： 是一组任务对应一个 CountDownLatch
        //有多少个人 计数器就指定为多少
        CountDownLatch countDownLatch = new CountDownLatch(tasks.length);
        //给每组一个任务设定相同的CountDownLatch
        for (int i = 0; i < tasks.length; i++) {
            tasks[i].setCountDownLatch(countDownLatch);
        }
        //每一个 task 都是 runnanle 类型 ，因此线程池执行它们
        for (int i = 0; i < tasks.length; i++) {
            //每一个线程执行开启任务，执行，
            executor.execute(tasks[i]);
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }
        return true;

    }

    /**
     * 给外界提供方法
     */
    public static boolean batch(Task ... tasks){
        return  createTasks(tasks);
    }


    /**
     * countDownLatch  测试方法
     *
     * @param args
     */
    public static void main(String[] args) {

        //利用CountDownLatch
        CountDownLatch countDownLatch = new CountDownLatch(3);
        Long startTime = System.currentTimeMillis();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                countDownLatch.countDown();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(6000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                countDownLatch.countDown();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(9000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                countDownLatch.countDown();
            }
        }).start();

        try {
            //卡住
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("总耗时" + (System.currentTimeMillis() - startTime + "毫秒"));
    }
}
